package com.liuxinlong.utils;

import ch.ethz.ssh2.*;
import com.liuxinlong.modules.entity.ShareFile;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.io.*;
import java.net.*;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

@Slf4j
public class FileUtils {
    private static final String USERNAME_PASSWORD = "pdmadmin@hotwater.com.cn" + ":" + "pA2016!";
    // 编码用户名和密码，拼接成认证信息
    private static final String AUTHOR = "Basic " + Base64.getEncoder().encodeToString(USERNAME_PASSWORD.getBytes());

    private static final int BUFFER = 8192;

    /*
     * 根据http路径下载文件保存到指定路径
     * urlString：文件路径
     * fileName：保存到本地的文件名称
     * filePath：本地要保存的指定路径
     * */
    public static boolean downloadFile(String urlString, String fileName, String filePath) {
        boolean bool = false;

        InputStream is = null;
        FileOutputStream os = null;

        try {
            log.info("文件路径：" + urlString);
            // 构造URL
            java.net.URL url = new java.net.URL(urlString);
            // 打开连接
            URLConnection con = url.openConnection();
//            con.setRequestProperty("Authorization", AUTHOR);
//            con.connect();
            // 输入流
            is = con.getInputStream();
            // 1K的数据缓冲
            byte[] bs = new byte[1024];
            // 读取到的数据长度
            int len;
            //判断文件的保存路径后面是否以/结尾
            if (!filePath.endsWith("/")) {
                filePath += "/";
            }
            //判断指定目录是否存在，不存在则先创建目录
            File file = new File(filePath);
            if (!file.exists())
                file.mkdirs();
            //fileName如果不包含文件后缀，则需要加上后缀，如：fileName + ".jpg";fileName + ".txt";
            os = new FileOutputStream(filePath + fileName, false);//false：覆盖文件,true:在原有文件后追加
            // 开始读取
            while ((len = is.read(bs)) != -1) {
                os.write(bs, 0, len);
            }

            bool = true;
            log.info("文件保存成功：" + fileName);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 完毕，关闭所有链接
            if (null != os) {
                try {
                    os.flush();
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (null != is) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return bool;
    }

    /**
     * 远程下载服务器文件
     *
     * @param ip             服务器ip
     * @param port           端口号
     * @param userName       用户名
     * @param password       密码
     * @param sourceFile     原文件路径
     * @param targetFile     目标文件路径
     * @param targetFileName 目标文件名称
     * @return 下载成功标识
     */

    public static boolean downloadCloudFile(String ip, int port, String userName, String password, String sourceFile, String targetFile, String targetFileName) {
        boolean bool = false;
        Connection conn = null;
        Session session = null;
        try {
            if (StringUtils.isEmpty(ip) || StringUtils.isEmpty(userName) || StringUtils.isEmpty(password) ||
                    StringUtils.isEmpty(sourceFile) || StringUtils.isEmpty(targetFile)) {
                return bool;
            }
            conn = new Connection(ip, port);
            conn.connect();
            boolean isAuth = conn.authenticateWithPassword(userName, password);
            if (!isAuth) {
                log.info("算法主机连接失败");
                return bool;
            }
            //执行命令
            session = conn.openSession();

            //执行命令并打印执行结果
            session.execCommand("df -h");
            InputStream staout = new StreamGobbler(session.getStdout());
            BufferedReader br = new BufferedReader(new InputStreamReader(staout));
            String line = null;
            while ((line = br.readLine()) != null) {
                System.out.println(line);
            }
            br.close();

            //下载文件到本地
            SCPClient scpClient = conn.createSCPClient();
            SCPInputStream scpis = scpClient.get(sourceFile);

            //判断指定目录是否存在，不存在则先创建目录
            File file = new File(targetFile);
            if (!file.exists())
                file.mkdirs();

            FileOutputStream fos = new FileOutputStream(targetFile + targetFileName);
            byte[] buffer = new byte[1024];
            int len = 0;
            while ((len = scpis.read(buffer)) != -1) {
                fos.write(buffer, 0, len);
            }
            fos.close();
            bool = true;
            //SFTP
            /*SFTPv3Client sftPClient = new SFTPv3Client(conn);
            sftPClient.createFile("");
            sftPClient.close();*/
        } catch (Exception e) {
            e.printStackTrace();
            log.info(e.getMessage());
            log.info("保存失败：" + sourceFile);
        } finally {
            if (null != session) {
                session.close();
            }
            if (null != conn) {
                conn.close();
            }
        }

        return bool;
    }

    /**
     * 获取目录下全部文件
     *
     * @param strPath 文件路径
     * @return 全部文件
     */
    public static List<File> getFileList(String strPath) {
        List<File> filelist = new ArrayList<>();
        File dir = new File(strPath);
        File[] files = dir.listFiles(); // 该文件目录下文件全部放入数组
        if (files != null) {
            for (int i = 0; i < files.length; i++) {
                String fileName = files[i].getName();
                if (files[i].isDirectory()) { // 判断是文件还是文件夹
                    getFileList(files[i].getAbsolutePath()); // 获取文件绝对路径
                } else { // 判断文件名
                    String strFileName = files[i].getAbsolutePath();
                    System.out.println("---" + strFileName);
                    filelist.add(files[i]);
                }
            }

        }
        return filelist;
    }

    /**
     * 获取目录下全部文件
     *
     * @param strPath 文件路径
     * @return 全部文件
     */
    public static List<ShareFile> getFilePathList(String strPath) {
        List<ShareFile> filelist = new ArrayList<>();
        File dir = new File(strPath);
        File[] files = dir.listFiles(); // 该文件目录下文件全部放入数组
        if (files != null) {
            for (int i = 0; i < files.length; i++) {
                String fileName = files[i].getName();
                if (files[i].isDirectory()) { // 判断是文件还是文件夹
                    getFileList(files[i].getAbsolutePath()); // 获取文件绝对路径
                } else { // 判断文件名
                    String strFileName = files[i].getAbsolutePath();
                    System.out.println("---" + strFileName);
                    ShareFile file = new ShareFile();
                    file.setFilePath(strFileName);
                    file.setFileName(fileName);
                    filelist.add(file);
                }
            }
        }
        return filelist;
    }

    /**
     * 复制文件夹及文件夹下全部内容
     *
     * @param sourcePath 原文件夹路径
     * @param newPath    目标文件夹路径
     */
    public static void copyDir(String sourcePath, String newPath) {
        try {
            (new File(newPath)).mkdirs();
            // 与mkdir()都创建文件夹 ，mkdirs()如果父文件夹不存在也会创建
            File fileList = new File(sourcePath);
            String[] strName = fileList.list();
            File temp = null;//游标
            for (int i = 0; i < strName.length; i++) {
                // 如果源文件路径以分隔符File.separator /或者\结尾那就sourcePath
                if (sourcePath.endsWith(File.separator)) {
                    temp = new File(sourcePath + strName[i]);
                } else {
                    temp = new File(sourcePath + File.separator + strName[i]);
                }
                if (temp.isFile()) {
                    // 如果游标遇到文件
                    FileInputStream in = new FileInputStream(temp);
                    // 复制且改名
                    File file = new File(newPath + "/" + temp.getName().toString());
                    FileOutputStream out = new FileOutputStream(file);
                    byte[] buffer = new byte[1024 * 8];
                    int length;
                    while ((length = in.read(buffer)) != -1) {

                        out.write(buffer, 0, length);
                    }
                    out.flush();
                    out.close();
                    in.close();
                }
                // 如果游标遇到文件夹
                if (temp.isDirectory()) {
                    copyDir(sourcePath + "/" + strName[i], newPath + "/" + strName[i]);
                }
            }
        } catch (Exception e) {
            System.out.println("文件夹复制失败!");
        }
    }

    /**
     * 压缩文件为zip
     *
     * @param filePath 文件路径
     * @param zipPath  要生成的zip压缩包路径
     * @return 是否压缩成功
     */
    public static boolean zipFile(String filePath, String zipPath) {
        ZipOutputStream out = null;
        try {
            out = new ZipOutputStream(new FileOutputStream(zipPath));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        //得到文件列表信息
        File file = new File(filePath);
        // 压缩zip包
        try {
            if (!file.exists()) {
                return false;
            }
            try (BufferedInputStream bis = new BufferedInputStream(Files.newInputStream(file.toPath()))) {

                ZipEntry entry = new ZipEntry(file.getName());
                out.putNextEntry(entry);
                int count;
                byte data[] = new byte[BUFFER];
                while ((count = bis.read(data, 0, BUFFER)) != -1) {
                    out.write(data, 0, count);
                }

            } catch (Exception e) {
                log.error(e.toString());
                return false;
            } finally {
                out.closeEntry();
            }
        } catch (Exception e) {
            log.error(e.toString());
            return false;
        } finally {
            try {
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        log.info("生成zip成功");
        System.out.println("生成zip成功");
        return true;
    }

    /**
     * 打包文件夹为zip
     *
     * @param filesPath 文件夹路径
     * @param zipPath   要生成的zip压缩包路径
     * @return 是否打包成功
     */
    public static boolean packageZip(String filesPath, String zipPath) {
        try {
            // 要被压缩的文件夹
            File file = new File(filesPath);   //需要压缩的文件夹
            File zipFile = new File(zipPath);  //放于和需要压缩的文件夹同级目录
            ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(zipFile));
            isDirectory(file, zipOut, "", true);   //判断是否为文件夹
            zipOut.close();
            return true;
        } catch (Exception e) {
            log.error(e.toString());
            return false;
        }
    }

    public static void isDirectory(File file, ZipOutputStream zipOutputStream, String filePath, boolean flag) {
        try {
            //判断是否为文件夹
            if (file.isDirectory()) {
                File[] files = file.listFiles();  //获取该文件夹下所有文件(包含文件夹)
                filePath = flag == true ? file.getName() : filePath + File.separator + file.getName();   //首次为选中的文件夹，即根目录，之后递归实现拼接目录
                for (int i = 0; i < files.length; ++i) {
                    //判断子文件是否为文件夹
                    if (files[i].isDirectory()) {
                        //进入递归,flag置false 即当前文件夹下仍包含文件夹
                        isDirectory(files[i], zipOutputStream, filePath, false);
                    } else {
                        //不为文件夹则进行压缩
                        InputStream input = new FileInputStream(files[i]);
                        zipOutputStream.putNextEntry(new ZipEntry(filePath + File.separator + files[i].getName()));
                        int temp = 0;
                        while ((temp = input.read()) != -1) {
                            zipOutputStream.write(temp);
                        }
                        input.close();
                    }
                }
            } else {
                //将子文件夹下的文件进行压缩
                InputStream input = new FileInputStream(file);
                zipOutputStream.putNextEntry(new ZipEntry(file.getPath()));
                int temp = 0;
                while ((temp = input.read()) != -1) {
                    zipOutputStream.write(temp);
                }
                input.close();
            }
        } catch (Exception e) {
            log.error(e.toString());
        }

    }
}
